﻿using System.Xml;
using System.Collections.Generic;
using System;
using System.Windows.Forms;
using System.Data;
using SdmxMl.Common;
using SdmxMl.Helper;

namespace SdmxMl.Structure
{
    /// <summary>
    /// OrganisationType provides a structure for describing agencies, data providers, 
    /// and data consumers and their contact information. The id attribute carries a code 
    /// identifying the agency. The version attribute indicates the version of the agency 
    /// description. The uri attribute provides a uri for an alternate way of identifying 
    /// the agency information (typically a URL resolving to an agency described in SDMX-ML). 
    /// Name is an element which provides for a human-readable name for the organization. 
    /// Description provides for a longer human-readable description of the organisation, 
    /// which may be provided in multiple, parallel language-equivalent forms. 
    /// MaintenanceContact provides contact information for the agency when acting as a 
    /// MaintenanceAgency; CollectorContact does the same when the agency is acting as a 
    /// statistics collector; DisseminatorContact for when the agency functions as a statistics 
    /// disseminator; and ReporterContact for when the Agency is functioning as a statistics reporter. 
    /// OtherContact is used to describe any other role. Note that the Role field in the contact 
    /// information structure should only be specified for OtherContact. It is allowable to 
    /// reference full Agency information by using (at a minimum) only the id, name, and uri fields, 
    /// with the uri pointing to an external description in a valid SDMX-ML Structure message 
    /// which provides more complete information. (This is termed an "external reference".) 
    /// If an external reference is being made, the isExternalReference attribute must be set to "true". 
    /// The urn attribute holds a valid SDMX Registry URN (see SDMX Registry Specification). 
    /// The parentOrganisation attribute holds the id of a parent organisation of the same type from 
    /// the same scheme, indicating that the organisation in question is a department or other sub-division 
    /// of the parent organisation. Annotations may be provided using the Annotations element, 
    /// in multiple, parallel-language form
    /// </summary>
    public class OrganisationType : BaseArtefact, IComparable,  ISdmxHierarchyListItem
    {
        #region Properties

        /// <summary>Simple hierarchy inside org is possible </summary>
        public string Parent { get; set; }
        public string ValidFrom { get; set; }
        public string ValidTo { get; set; }
        public string Urn { get; set; }
        public string Uri { get; set; }

        // No use for flat hierarchy
        public IHierarchyManage InnerHierarchy
        {
            get { return null; }
        }

        public bool IsExternalReference { get; set; }
        public  ContactType MaintenanceContact { get; set; }
        public ContactType CollectorContact { get; set; }
        public ContactType DisseminatorContact { get; set; }
        public ContactType ReporterContact { get; set; }
        public ContactTypeList OtherContactList { get; set; }

        #endregion

        #region Constructor

        private void Init()
        {
            OtherContactList = new ContactTypeList();
            MaintenanceContact = new ContactType();
            CollectorContact = new ContactType();
            DisseminatorContact = new ContactType();
            ReporterContact = new ContactType();
        }

        public OrganisationType()
        {
            Init();
        }

        public OrganisationType(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr) 
            : base(nodeArtefact, nsmgr)
        { 
            Init();
            Parent = Xmlhelper.GetAtt(nodeArtefact, "parentOrganisation");
            ValidFrom = Xmlhelper.GetAtt(nodeArtefact, "validFrom");
            ValidTo = Xmlhelper.GetAtt(nodeArtefact, "validTo");
            Urn = Xmlhelper.GetAtt(nodeArtefact, "urn");
            Uri = Xmlhelper.GetAtt(nodeArtefact, "uri");
            IsExternalReference = Xmlhelper.GetAtt(nodeArtefact, "isExternalReference").ToLower() == "true";

            // The contacts
            MaintenanceContact = new ContactType(nodeArtefact, nsmgr, "MaintenanceContact");
            CollectorContact = new ContactType(nodeArtefact, nsmgr, "CollectorContact");
            DisseminatorContact = new ContactType(nodeArtefact, nsmgr, "DisseminatorContact");
            ReporterContact = new ContactType(nodeArtefact, nsmgr, "ReporterContact");
            OtherContactList.AddContactsFromNode(nodeArtefact, nsmgr, "OtherContact");

            //To remove
            /*
            if (maintenanceContact.Name.TextList.Count == 1)
                maintenanceContact.Name.TextList.Add(new TextType("fr", maintenanceContact.Name.TextList[0].Text));

            foreach (ContactType ct in otherContactList)
                if (ct.Name.TextList.Count == 1)
                    ct.Name.TextList.Add(new TextType("fr", ct.Name.TextList[0].Text));
             * */
        }

        #endregion

        #region Clone

        public ISdmxHierarchyListItem Clone()
        {
            OrganisationType c = new OrganisationType();

            c.Id = Id;
            c.Name = Name.Clone();
            c.Description = Description.Clone();
            c.Uri = Uri;
            c.Urn = Urn;
            c.ValidFrom = ValidFrom;
            c.ValidTo = ValidTo;

            c.AnnotationList = AnnotationList.Clone();
            c.Parent = string.Empty;

            foreach (ContactType contact in OtherContactList)
                c.OtherContactList.Add(contact.Clone());

            c.MaintenanceContact = MaintenanceContact.Clone();
            c.CollectorContact = CollectorContact.Clone();
            c.DisseminatorContact = DisseminatorContact.Clone();
            c.ReporterContact = ReporterContact.Clone();

            return c;
        }
        #endregion

        #region XML serialize
        
        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            xw.WriteStartElement(prefix, tag, null);
            // id required
            if (string.IsNullOrEmpty(Id))
                Id = "undefined";
            xw.WriteAttributeString("id", Id);

            Xmlhelper.WriteAttributeIfExist(xw, "version", Version);
            Xmlhelper.WriteAttributeIfExist(xw, "uri", Uri);
            Xmlhelper.WriteAttributeIfExist(xw, "urn", Urn);
            if (IsExternalReference)
                xw.WriteAttributeString("isExternalReference", IsExternalReference.ToString().ToLower());
            Xmlhelper.WriteAttributeIfExist(xw, "parentOrganisation", Parent);
            Xmlhelper.WriteAttributeIfExist(xw, "validFrom", ValidFrom);
            Xmlhelper.WriteAttributeIfExist(xw, "validTo", ValidTo);

            Name.WriteXml(xw, prefix, "Name");
            Description.WriteXml(xw, prefix, "Description");

            MaintenanceContact.WriteXml(xw, prefix, "MaintenanceContact");
            CollectorContact.WriteXml(xw, prefix, "CollectorContact");
            DisseminatorContact.WriteXml(xw, prefix, "DisseminatorContact");
            ReporterContact.WriteXml(xw, prefix, "ReporterContact");
            foreach (ContactType ct in OtherContactList)
                ct.WriteXml(xw, prefix, "OtherContact");


            // Annotations
            AnnotationList.WriteXml(xw, prefix, null);
            
            xw.WriteEndElement();

        }
        #endregion

        #region Tree

        public int UsedImageIndex
        {
            get
            {
                return MaintenanceContact.Name.IsEmpty == false ? 4 : 0;
            }
        }

        public override TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = base.FillNode(parentNode);
            t.ImageIndex = t.SelectedImageIndex = UsedImageIndex;

            return t;
        }

        #endregion

        #region String Representation

        public override string ToString()
        {
            return Id + " - " + Name.ToString(); ;
        }
        #endregion

        #region IComparable Members

        public int CompareTo(object obj)
        {
            OrganisationType mc = (OrganisationType)obj;

            if (mc == null)
                return -1;

            return string.Compare(this.Id, mc.Id, true);
        }

        #endregion
    }

    public class AgenciesType : FlatHierarchicalList
    {
        public AgenciesType()
            : base("Code", "Description")
        {
        }

        public override ISdmxHierarchyListItem CreateNewItem()
        {
            return new OrganisationType();
        }

        public override ISdmxHierarchyListItem CreateNewItem(XmlNode nd, SdmxNamespaceManager nsmgr)
        {
            return new OrganisationType(nd, nsmgr);
        }

        public override string ToString()
        {
            return "Agencies";
        }
    }

    public class DataProvidersType : AgenciesType
    {
        public override string ToString()
        {
            return "DataProviders";
        }
    }


    public class DataConsumersType : AgenciesType
    {
        public override string ToString()
        {
            return "DataConsumers";
        }
    }
}
